import { Scene } from '@babylonjs/core/scene';
import { Geometry } from '@babylonjs/core/Meshes/geometry';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import { Calculation } from '../tool/calculation';
import { Buffer } from '@babylonjs/core/Buffers/buffer';

/**
 * 基础线几何体参数对象
 * @param autoUpdateDistances 是否自动更新线长度值
 */
interface IBasicLineGeometryOptions {
    autoUpdateDistances?: boolean,
}


/**
 * 基础线（gl-line）几何体
 * @param id 几何体的id
 * @param vertices 顶点集合
 * @param options 参数对象
 * @param scene 所在的场景
 */
class BasicLineGeometry extends Geometry {

    private _verts: Vector3[];
    private _count: number = 0;
    private _pos!: Float32Array;
    private _dis!: Float32Array;
    private _ta0: number[] = [];
    private _idx: number[] = [];
    private _autoUpdateDistances: boolean;

    constructor(id: string, vertices: Vector3[], options?: IBasicLineGeometryOptions, scene?: Scene) {
        super(id, scene, undefined, true);
        const ops = options || {};
        this._autoUpdateDistances = ops.autoUpdateDistances || false;
        this._verts = vertices;
        this.setVertexData();
        this.updateDistance();
        this.updateAttributes();
    }

    /**
     * 设置顶点
     */
    public set vertices(points: Vector3[]) {
        this._verts = points;
        this.setVertexData();
        if (this._autoUpdateDistances) this.updateDistance();
        this.updateAttributes();
    }

    /**
     * 获取顶点
     */
    public get vertices(): Vector3[] {
        return this._verts;
    }

    /**
     * 更新距离值（如果需要，应在顶点改变后调用）
     */
    public updateDistance(): void {
        const ta0 = this._ta0;
        const vts = this._verts;
        const dis = this._dis;
        ta0.length = 0;
        Calculation.distancesOfPoints(vts, ta0);
        for (let i = 0; i < vts.length; i++) {
            dis[i] = ta0[i];
        }
        this.getVertexBuffer('lineDistance')?.update(dis);
    }

    /**
     * 更新属性
     */
    private updateAttributes(): void {
        this.getVertexBuffer('position')?.update(this._pos);
        this.applyIndices();
    }

    /**
     * 设置顶点数据
     */
    private setVertexData(): void {
        const engine = this.getEngine();
        const vts = this._verts;
        this._count = vts.length;

        if ((!this._dis) || (this._count > this._dis.length)) {
            this._pos = new Float32Array(this._count * 3 * 2);
            this._dis = new Float32Array(this._count * 2);

            let bfr = this.getVertexBuffer('position');
            if (bfr) bfr.dispose();
            const verticesRefBuffer = new Buffer(engine, this._pos, true, 3);
            this.setVerticesBuffer(verticesRefBuffer.createVertexBuffer('position', 0, 3));

            bfr = this.getVertexBuffer('lineDistance');
            if (bfr) bfr.dispose();
            const lineDistanceRefBuffer = new Buffer(engine, this._dis, true, 1);
            this.setVerticesBuffer(lineDistanceRefBuffer.createVertexBuffer('lineDistance', 0, 1));
        }

        for (let i = 0; i < vts.length; i++) {
            const p = vts[i];
            this._pos[i * 3] = p.x;
            this._pos[i * 3 + 1] = p.y;
            this._pos[i * 3 + 2] = p.z;
        }

    }

    /**
     * 设置索引
     */
    private applyIndices(): void {
        const s = this._count;
        const indices = this._idx;
        indices.length = 0;
        for (let i = 0; i < s; i++) {
            indices.push(i);
        }

        this.setIndices(indices, s);
    }
}


export { BasicLineGeometry };